//
//  SwipeableCell.swift
//  ShimaPlayer
//
//  Created by michael on 2025/7/17.
//

import UIKit

/// A protocol that any view used as content in SwipeableCell must conform to
protocol SwipeableCellContent: UIView {
    /// Method called when the cell is configured with a model
    func configure<Model>(with model: Model)
}

/// A custom UITableViewCell that supports generic content view and swipe actions
class SwipeableCell<ContentView: SwipeableCellContent>: UITableViewCell {
    
    // MARK: - Properties
    
    /// The content view that will be displayed in the cell
    private(set) var customContentView: ContentView
    
    /// Container view that holds the content and can be swiped
    private let containerView = UIView()
    
    private let bgView = UIView()
    
    /// View that contains action buttons
    private let actionsContainerView = UIView()
    
    /// Array of action buttons
    private var actionButtons: [UIButton] = []
    
    /// Flag to track if cell is open
    private var isOpen = false
    
    /// Original position of the container view
    private var originalCenter: CGPoint = .zero
    
    /// Flag to track if the current gesture is horizontal
    private var isHorizontalGesture = false
    
    /// Maximum distance the cell can be swiped
    private var maxSwipeDistance: CGFloat = 0
    
    /// Maximum shadow opacity
    private let maxShadowOpacity: Float = 1
    
    /// Shadow radius when fully open
    private let maxShadowRadius: CGFloat = 4.0
    
    /// Shadow animation duration
    private let shadowAnimationDuration: TimeInterval = 0.2
    
    /// Flag to determine if shadow effect is enabled
    private var isShadowEnabled: Bool = false
    
    /// Pan gesture recognizer for handling swipes
    private lazy var panGestureRecognizer: UIPanGestureRecognizer = {
        let gesture = UIPanGestureRecognizer(target: self, action: #selector(handlePan(_:)))
        return gesture
    }()
    
    /// Threshold for considering a swipe action triggered
    private let swipeThreshold: CGFloat = 0.5
    
    /// Bounce back animation duration
    private let bounceAnimationDuration: TimeInterval = 0.3
    
    // MARK: - Initialization
    
    /// Initialize with a content view
    init(contentView: ContentView) {
        self.customContentView = contentView
        super.init(style: .default, reuseIdentifier: nil)
        setupViews()
    }
    
    /// Required initializer for UITableViewCell that's called when dequeuing from a table view
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        self.customContentView = ContentView()
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    // MARK: - View Setup
    
    private func setupViews() {
        selectionStyle = .none
        backgroundColor = .clear
        
        // Setup container view
        containerView.backgroundColor = .clear
        
        // Setup shadow properties (initially hidden)
        bgView.layer.shadowColor = UIColor(hexString: "#000000")?.withAlphaComponent(0.1).cgColor
        bgView.layer.shadowOffset = CGSize(width: 4, height: 0)
        bgView.layer.shadowOpacity = 0
        bgView.layer.shadowRadius = 0
        bgView.layer.masksToBounds = false
        
        // Add pan gesture recognizer
        panGestureRecognizer.delegate = self
        containerView.addGestureRecognizer(panGestureRecognizer)
        
        // Setup actions container
        actionsContainerView.backgroundColor = .blue
        
        // Add views to hierarchy
        contentView.addSubview(bgView)
        contentView.addSubview(actionsContainerView)
        contentView.addSubview(containerView)
        containerView.addSubview(customContentView)
        
        // Add tap gesture to close when tapping elsewhere
        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(_:)))
        tapGesture.cancelsTouchesInView = false
        tapGesture.delegate = self
        contentView.addGestureRecognizer(tapGesture)
        
        // Setup constraints
        bgView.translatesAutoresizingMaskIntoConstraints = false
        containerView.translatesAutoresizingMaskIntoConstraints = false
        actionsContainerView.translatesAutoresizingMaskIntoConstraints = false
        customContentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            bgView.topAnchor.constraint(equalTo: contentView.topAnchor),
            bgView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            bgView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 20),
            bgView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -20),
            
            // Container constraints
            containerView.topAnchor.constraint(equalTo: contentView.topAnchor),
            containerView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
            containerView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            containerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            
            // Actions container constraints
            actionsContainerView.topAnchor.constraint(equalTo: containerView.topAnchor),
            actionsContainerView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
            actionsContainerView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
            // Width will be updated when buttons are added
            
            // Content view constraints
            customContentView.topAnchor.constraint(equalTo: containerView.topAnchor),
            customContentView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor),
            customContentView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor),
            customContentView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor)
        ])
    }
    
    // MARK: - Public Methods
    
    /// Configure the cell with a model
    func configure<Model>(with model: Model) {
        customContentView.configure(with: model)
    }

    func cornerRadius(_ radius: CGFloat){
        actionsContainerView.layer.cornerRadius = radius + 2
        actionsContainerView.clipsToBounds = true
        containerView.layer.cornerRadius = radius
        containerView.layer.masksToBounds = true
//        return self
    }
    
    func actionsContainerViewBackgroundColor(_ color: UIColor?) {
        bgView.backgroundColor = color
//        containerView.backgroundColor = color
    }
    
    /// Enable or disable shadow effect
    /// - Parameter enabled: Whether shadow effect should be enabled
    /// - Returns: Self for method chaining
    @discardableResult
    func enableShadow(_ enabled: Bool = true) -> Self {
        isShadowEnabled = enabled
        
        // If disabled, immediately remove any existing shadow
        if !enabled {
            bgView.layer.shadowOpacity = 0
            bgView.layer.shadowRadius = 0
        } else if isOpen {
            // If cell is already open and shadow is being enabled, show shadow
            updateShadowForOffset(maxSwipeDistance)
        }
        
        return self
    }
    
    /// Add a swipe action to the cell
    /// - Parameters:
    ///   - title: The title of the action button
    ///   - backgroundColor: The background color of the button
    ///   - textColor: The text color of the button (defaults to white)
    ///   - fontSize: The font size of the button text (defaults to 15)
    ///   - buttonWidth: The width of the button (defaults to 80)
    ///   - handler: The action to perform when the button is tapped
    @discardableResult
    func addAction(title: String, backgroundColor: UIColor?, textColor: UIColor = .white, fontSize: CGFloat = 15, buttonWidth: CGFloat = 80, handler: @escaping () -> Void) -> Self {
        let button = UIButton(type: .system)
        button.titleLabel?.numberOfLines = 0
        button.titleLabel?.textAlignment = .center
        button.setTitle(title, for: .normal)
        button.backgroundColor = backgroundColor
        button.setTitleColor(textColor, for: .normal)
        button.titleLabel?.font = .systemFont(ofSize: fontSize, weight: .medium)
        button.tag = Int(buttonWidth) // Store button width in tag for later use
        button.addAction(UIAction { _ in handler() }, for: .touchUpInside)
        
        actionButtons.append(button)
        actionsContainerView.addSubview(button)
        
        actionsContainerView.backgroundColor = .clear
        
        updateActionButtonsLayout()
        
        return self
    }
    
    /// Reset the cell to its original position
    func resetPosition(animated: Bool = true) {
        isOpen = false
        if animated {
            UIView.animate(withDuration: bounceAnimationDuration) {
                self.containerView.center.x = self.contentView.center.x
                self.updateShadowForOffset(0)
            }
        } else {
            containerView.center.x = contentView.center.x
            updateShadowForOffset(0)
        }
    }
    
    /// Open the swipe actions
    private func openSwipeActions() {
        isOpen = true
        UIView.animate(withDuration: bounceAnimationDuration) {
            self.containerView.center.x = self.contentView.center.x - self.maxSwipeDistance
            self.updateShadowForOffset(self.maxSwipeDistance)
        }
    }
    
    /// Update shadow based on swipe offset
    private func updateShadowForOffset(_ offset: CGFloat) {
        // If shadow is disabled, don't update anything
        if !isShadowEnabled {
            return
        }
        
        // Calculate shadow properties based on swipe progress (0 to 1)
        let progress = min(offset / maxSwipeDistance, 1.0)
        
        // Update shadow properties with animation if needed
        if isOpen || offset > 0 {
            UIView.animate(withDuration: shadowAnimationDuration) {
                self.bgView.layer.shadowOpacity = Float(progress) * self.maxShadowOpacity
                self.bgView.layer.shadowRadius = progress * self.maxShadowRadius
            }
        } else {
            // Immediately hide shadow when fully closed
            bgView.layer.shadowOpacity = 0
            bgView.layer.shadowRadius = 0
        }
    }
    
    /// Handle tap gesture to close cell if open
    @objc private func handleTap(_ gesture: UITapGestureRecognizer) {
        if isOpen {
            resetPosition()
        }
    }
    
    // MARK: - Private Methods
    
    private func updateActionButtonsLayout() {
        // Remove existing constraints
        actionButtons.forEach { $0.removeConstraints($0.constraints) }
        
        // Calculate total width based on individual button widths
        var totalWidth: CGFloat = 0
        let buttonWidths = actionButtons.map { CGFloat($0.tag) } // Get widths from button tags
        
        // If no custom widths set, use default
        if buttonWidths.contains(where: { $0 > 0 }) {
            totalWidth = buttonWidths.reduce(0, +)
        } else {
            totalWidth = CGFloat(actionButtons.count) * 80
        }
        
        maxSwipeDistance = min(totalWidth, 240) // Limit max swipe distance
        
        // Update actions container width constraint
        for constraint in actionsContainerView.constraints where constraint.firstAttribute == .width {
            constraint.isActive = false
        }
        actionsContainerView.widthAnchor.constraint(equalToConstant: maxSwipeDistance).isActive = true
        
        // Add constraints for each button
        for (index, button) in actionButtons.enumerated() {
            button.translatesAutoresizingMaskIntoConstraints = false
            
            // Get button width from tag or use default
            let width = button.tag > 0 ? CGFloat(button.tag) : 80
            
            NSLayoutConstraint.activate([
                button.topAnchor.constraint(equalTo: actionsContainerView.topAnchor),
                button.bottomAnchor.constraint(equalTo: actionsContainerView.bottomAnchor),
                button.widthAnchor.constraint(equalToConstant: width)
            ])
            
            // Position buttons from right to left
            if index == 0 {
                button.trailingAnchor.constraint(equalTo: actionsContainerView.trailingAnchor).isActive = true
            } else {
                button.trailingAnchor.constraint(equalTo: actionButtons[index - 1].leadingAnchor).isActive = true
            }
        }
    }
    
    // MARK: - Gesture Handling
    
    @objc private func handlePan(_ gesture: UIPanGestureRecognizer) {
        switch gesture.state {
        case .began:
            originalCenter = containerView.center
            isHorizontalGesture = false
            
        case .changed:
            let translation = gesture.translation(in: containerView)
            let velocity = gesture.velocity(in: containerView)
            
            // 在手势开始时判断方向
            if !isHorizontalGesture {
                // 判断是否为水平手势
                if abs(translation.x) > 10 || abs(velocity.x) > 100 {
                    isHorizontalGesture = abs(translation.x) > abs(translation.y) && abs(velocity.x) > abs(velocity.y)
                }
                
                // 如果不是水平手势，不处理
                if !isHorizontalGesture && (abs(translation.x) > 10 || abs(velocity.x) > 100) {
                    return
                }
            }
            
            // 只在确认是水平手势时才处理
            if isHorizontalGesture {
                // Only allow swiping left (negative x)
                if translation.x <= 0 {
                    let newCenterX = originalCenter.x + translation.x
                    // Limit the swipe distance
                    let limitedCenterX = max(originalCenter.x - maxSwipeDistance, newCenterX)
                    containerView.center.x = limitedCenterX
                    
                    // Calculate shadow based on swipe progress
                    updateShadowForOffset(abs(translation.x))
                } else if isOpen {
                    // Allow swiping right to close if already open
                    let newCenterX = originalCenter.x + translation.x
                    // Don't go beyond original position
                    let limitedCenterX = min(self.contentView.center.x, newCenterX)
                    containerView.center.x = limitedCenterX
                    
                    // Calculate shadow based on remaining open distance
                    let openDistance = self.contentView.center.x - limitedCenterX
                    updateShadowForOffset(openDistance)
                }
            }
            
        case .ended, .cancelled:
            // 只在水平手势时才处理结束事件
            if isHorizontalGesture {
                let velocity = gesture.velocity(in: containerView)
                let translation = containerView.center.x - originalCenter.x
                
                // If swiped more than threshold or with high velocity
                if abs(translation) > maxSwipeDistance * swipeThreshold || abs(velocity.x) > 500 {
                    if translation < 0 { // Swiped left - open
                        openSwipeActions()
                    } else if isOpen { // Swiped right - close
                        resetPosition()
                    }
                } else {
                    // Return to previous state
                    if isOpen {
                        openSwipeActions()
                    } else {
                        resetPosition()
                    }
                }
            }
            
            // 重置手势方向标记
            isHorizontalGesture = false
            
        default:
            break
        }
    }
    
    // MARK: - Lifecycle
    
    override func prepareForReuse() {
        super.prepareForReuse()
        resetPosition(animated: false)
    }
    

    // MARK: - UIGestureRecognizerDelegate
    
    override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        // 允许与 TableView 的滚动手势同时工作
        if gestureRecognizer == panGestureRecognizer {
            // 如果是垂直滚动，允许同时识别
            if let panGesture = gestureRecognizer as? UIPanGestureRecognizer {
                let velocity = panGesture.velocity(in: self)
                let translation = panGesture.translation(in: self)
                
                // 如果是垂直方向的手势，允许同时识别
                if abs(velocity.y) > abs(velocity.x) || abs(translation.y) > abs(translation.x) {
                    return true
                }
            }
        }
        return false
    }
    
    override func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
        // Allow tap gesture to work only when cell is open
        if gestureRecognizer is UITapGestureRecognizer {
            return isOpen
        }
        return true
    }
    
    // 新增：手势开始时的判断
    override func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
        if gestureRecognizer == panGestureRecognizer {
            let panGesture = gestureRecognizer as! UIPanGestureRecognizer
            let velocity = panGesture.velocity(in: self)
            let translation = panGesture.translation(in: self)
            
            // 只在水平方向的手势时才开始识别
            // 如果是垂直方向的手势，不要开始识别
            if abs(velocity.y) > abs(velocity.x) * 2 || abs(translation.y) > abs(translation.x) * 2 {
                return false
            }
            
            // 如果是向右滑动且没有打开，不要开始识别
            if translation.x > 0 && !isOpen {
                return false
            }
        }
        return true
    }
}

// MARK: - Example Content View Implementation

/// Example implementation of a content view for the SwipeableCell
class ExampleContentView: UIView, SwipeableCellContent {
    private let titleLabel = UILabel()
    private let subtitleLabel = UILabel()
    
    init() {
        super.init(frame: .zero)
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupViews() {
        backgroundColor = .white
        
        titleLabel.font = .systemFont(ofSize: 16, weight: .medium)
        titleLabel.textColor = .black
        
        subtitleLabel.font = .systemFont(ofSize: 14)
        subtitleLabel.textColor = .gray
        
        let stackView = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel])
        stackView.axis = .vertical
        stackView.spacing = 4
        
        addSubview(stackView)
        stackView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16),
            stackView.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16),
            stackView.centerYAnchor.constraint(equalTo: centerYAnchor)
        ])
    }
    
    func configure<Model>(with model: Model) {
        if let item = model as? CollectionItemModel {
            titleLabel.text = item.title
            subtitleLabel.text = "Count: \(item.count)"
        }
    }
}
